﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace NeurOthello.Logic
{
    public abstract class Othello
    {
        public static int boardSize = 8;
        protected const int player1 = 1, player2 = 2, nSquares = 64;  

        private static int DIRECTIONS = 8;
        public static double NullToken = -999999;

        public abstract int[,] Gameboard { get; }
        public abstract double[] Inputboard { get; }

        private int playerTurn = 1;
        public int PlayerTurn { get; set; }
        public int Opponent { get { return 3 - playerTurn; } }
        
        public Othello()
        {

        }

        public int playGame(NeuroPlayer player, MiniMax opponent)
        {
            ResetBoard();
            int currentP = 1;
            while (true)
            {
                if (HasMove(currentP))
                {
                    if (currentP == 1) 
                        PlaceMarker(currentP, player.MakeMove(currentP));
                    else
                        PlaceMarker(currentP, opponent.RunMiniMax(currentP, true, 2));
                   
                }
                currentP = 3 - currentP;              

                if (!HasMove(1) && !HasMove(2))
                    break;
            }
            int b = 0, w= 0, u = 0;
            boardCount(ref b, ref w, ref u);
    
            if (b > w)
            {                

                return 1; 
            }
            if (b < w)
            {

                return 2;
            }
            else
            {

                return 0;
            }
        }

        public int playGame(MiniMax player, MiniMax opponent)
        {
            ResetBoard();
            int currentP = 1;
            while (true)
            {
                if (HasMove(currentP))
                {
                    if (currentP == 1)
                        PlaceMarker(currentP, player.RunMiniMax(currentP, true, 3));
                    else
                        PlaceMarker(currentP, opponent.RunMiniMax(currentP, true, 1));

                }
                currentP = 3 - currentP;

                if (!HasMove(1) && !HasMove(2))
                    break;
            }
            int b = 0, w = 0, u = 0;
            boardCount(ref b, ref w, ref u);

            if (b > w)
            {

                return 1;
            }
            if (b < w)
            {

                return 2;
            }
            else
            {

                return 0;
            }
        }

        public int playTrainingGame(NeuroPlayer player, double r, double learning)
        {
            ResetBoard();
            PlayerTurn = 1;
            while (PlayerTurn != 0)
            {
                switch (PlayerTurn)
                {
                    case (player1):
                        PlaceMarker(player1, player.MakeTrainingMove(player1, r, learning));
                        break;
                    case (player2):
                        PlaceMarker(player2, player.MakeTrainingMove(player2, r, learning));
                        break;
                }
            }
            int b = 0, w = 0, u = 0;
            boardCount(ref b, ref w, ref u);

            if (b > w)
            {
                player.TrainPlayer(new double[2] { 1, 0 }, learning);
                return 1;
            }
            else if (b < w)
            {
                player.TrainPlayer(new double[2] { 0, 1 }, learning);
                return 2;
            }
            else
            {
                player.TrainPlayer(new double[2] { 0.5, 0.5 }, learning);
                return 0;
            }
        }

        public abstract void ResetBoard();

        public abstract void SetSquare(int x, int y, int playerId);

        public abstract bool PlaceMarker(int playerId, int x, int y);

        public abstract bool PlaceMarker(int playerId, Position pos);

        public abstract bool HasMove(int playerId);

        public abstract int CountMoves(int playerId);

        public abstract void ClearTranspositions();

        public abstract void AddTranspositionValue(double val);

        public abstract double FindTranspositionValue();

        public abstract Position[] AllMoves(int playerId);

        public abstract void boardCount(ref int black, ref int white, ref int unMarked);

        public abstract int SafeScore(int playerId);
    }
}
